/**
 * @brief XML基类头文件
 * @author zhangpeihao
 */

#include <tinyxml/tinyxml.h>

#include <zsystem/core/common/types.h>
#include <zsystem/core/common/assert.h>
#include <zsystem/core/common/memory.h>

#pragma once

namespace zsystem {

  typedef TiXmlElement* xmlNode;

	/**
	 * @brief XML基类
	 */
	class xmlbase {
	public:
		/**
		 * @brief 构造函数
		 */
		xmlbase()
    :_doc(Z_NULL)
		{
      _doc = Z_NEW(TiXmlDocument) ();
      Z_ASSERT_SYS_ALIGN(_doc);
		}

		///析构函数
		virtual ~xmlbase(){
      Z_SAFE_DELETE(_doc, ~TiXmlDocument);
		}

    /**
		 * @brief 得到根节点
		 * @param[in,out] rootNode 根结点
		 * @return 成功或失败
		 */
    const Z_BOOL getRootNode(xmlNode& rootNode){
      if(Z_NULL == _doc)
        return Z_FALSE;
      rootNode = _doc->RootElement();
      return Z_TRUE;
    }

		/**
		 * @brief 得到子节点
		 * @param[in] parentNode 父节点
		 * @param[in] nodeName 子节点名
		 * @param[in,out] childNode 节点
 		 * @param[in] index 索引值（默认为：0,表示第一个）
		 * @return 成功或失败
		 */
    const Z_BOOL getChildNode(const xmlNode parentNode, const char* nodeName, xmlNode& childNode, Z_U32 index = 0){
      if (Z_NULL == parentNode)
        return Z_FALSE;
      xmlNode node = parentNode->FirstChildElement(nodeName);

      for(Z_U32 i = 0; i < index && Z_NULL != node; i++)
      {
        node = node->NextSiblingElement(nodeName);
      }
      if (node != Z_NULL)
      {
        childNode = node;
        return Z_TRUE;
      }
      return Z_FALSE;
    }

		/**
		 * @brief 得到子节点
		 * @param[in] nodeName 节点名
		 * @param[in] parentNode 父节点
 		 * @param[in] index 索引值（默认为：0,表示第一个）
		 * @return node 子节点，如果没找到，返回Z_NULL
		 */
    xmlNode getChildNode(const xmlNode parentNode, const char* nodeName, Z_U32 index = 0){
      if (Z_NULL == parentNode)
        return Z_NULL;
      xmlNode node = parentNode->FirstChildElement(nodeName);

      for(Z_U32 i = 0; i < index && Z_NULL != node; i++)
      {
        node = node->NextSiblingElement(nodeName);
      }
      return node;
    }
		/**
		 * @brief 得到子节点
		 * @param[in] parentNode 父节点
		 * @param[in] nodeName 节点名路径（/分隔）
		 * @param[in,out] childNode 节点
		 * @return 成功或失败
		 */
    const Z_BOOL getChildNodeByPath(const xmlNode parentNode, const char* nodePath, xmlNode& childNode);

		/**
		 * @brief 通过路径得到子节点
		 * @param[in] parentNode 父节点
		 * @param[in] nodePath 节点名路径（/分隔）
		 * @return node 子节点，如果没找到，返回Z_NULL
		 */
    xmlNode getChildNodeByPath(const xmlNode parentNode, const char* nodePath);

		/**
		 * @brief 得到下一个节点
		 * @param[in] currentNode 当前节点
		 * @param[in] nodeName 节点名
		 * @param[in,out] nextNode 节点
		 * @return 成功或失败
		 */
    const Z_BOOL getNextSibling(xmlNode currentNode, const char* nodeName, xmlNode& nextNode){
      if (Z_NULL == currentNode)
      {
        return Z_FALSE;
      }
      xmlNode node = currentNode->NextSiblingElement(nodeName);
      if (node == Z_NULL)
      {
        return Z_FALSE;
      }
      else
      {
        nextNode = node;
        return Z_TRUE;
      }
    }

		/**
		 * @brief 得到下一个节点
		 * @param[in] currentNode 当前节点
		 * @param[in] nodeName 节点名
		 * @return node 下一个节点节点，如果没找到，返回Z_NULL
		 */
    xmlNode getNextSibling(xmlNode currentNode, const char* nodeName){
      if (Z_NULL == currentNode)
      {
        return Z_NULL;
      }
      return currentNode->NextSiblingElement(nodeName);
    }

		/**
		 * @brief 读取数据
		 * @param[in] node 节点
		 * @param[in,out] value 数值
		 * @return 成功或失败
		 */
    template<typename TYPE>
	  const Z_BOOL read(const xmlNode node, TYPE& value);

		/**
		 * @brief 得到属性
		 * @param[in] node 节点
		 * @param[in,out] value 值
		 * @param[in] attrName 属性名
		 * @return 成功或失败
		 */
    template<typename TYPE>
		const Z_BOOL readAttribute(const xmlNode node, TYPE& value, const char* attrName);

		/**
		 * @brief 得到某个项目的数目
		 * @param[in] node 节点
		 * @param[in] node_name 项目名
		 * @param[in,out] number 数量
		 * @return 成功或失败
		 */
		const Z_BOOL getNumber(const xmlNode parentNode, const char* nodeName, Z_U32& number);

		/**
		 * @brief 得到某个项目的数目
		 * @param[in] node 节点
		 * @param[in] node_name 项目名
		 * @return 数量
		 */
		const Z_U32 getNumber(const xmlNode parentNode, const char* nodeName);

    /**
		 * @brief 解析
		 * @param[in] str 字符串
		 * @param[in,out] value 数值
		 * @return const Z_BOOL 成功或失败
		 */
    template<typename TYPE>
		static const Z_BOOL parse(const char* str, TYPE& value);
  private:

    /**
		 * @brief 解析有符号整数
		 * @param[in] str 字符串
		 * @param[in,out] value 数值
		 * @return const Z_BOOL 成功或失败
		 */
    template<typename TYPE>
		static const Z_BOOL parseSigned(const char* str, TYPE& value);

		/**
		 * @brief 解析无符号整数
		 * @param[in] str 字符串
		 * @param[in,out] value 数值
		 * @return const Z_BOOL 成功或失败
		 */
    template<typename TYPE>
		static const Z_BOOL parseUnsigned(const char* str, TYPE& value);

		/**
		 * @brief 解析小数
		 * @param[in] str 字符串
		 * @param[in,out] value 数值
		 * @return const Z_BOOL 成功或失败
		 */
    template<typename TYPE>
		static const Z_BOOL parseFloat(const char* str, TYPE& value);

		/**
		 * @brief 解析Bool
		 * @param[in] str 字符串
		 * @param[in,out] value 数值
		 * @return const Z_BOOL 成功或失败
		 */
		static const Z_BOOL parseBoolean(const char* str, Z_BOOL& value);
  protected:
		/**
		 * @brief 解析Path（用/分隔节点）
		 * @param[in,out] point Path字符串指针
		 * @param[in,out] result 一个分配好空间的字符串。（返回空字符串表示解析错误）
		 * @return const Z_BOOL 是否解析结束（Z_FALSE - 还未结束，Z_TRUE - 已经结束）
		 */
    const Z_BOOL nextNodeInPath(const char*& path, char* result);

	private:
		/**
		 * @brief Copy构造函数
		 * @param[in] config。
		 * @remark 禁用
		 */
		inline xmlbase( xmlbase& config ){
			Z_ASSERT(false);
		}
		/**
		 * @brief 赋值
		 * @param[in] config。
		 * @remark 禁用
		 */
		inline xmlbase& operator=(const xmlbase& config ){
			Z_ASSERT(false);
			return *this;
		}

  protected:
    TiXmlDocument* _doc;
		
	};

} 
 
